﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using resharperupdate.core.dto;
using resharperupdate.core.dto.impl;
using resharperupdate.core.services.impl;

namespace resharperupdate.core.controllers.impl
{
    public class UpdaterController : IUpdaterController
    {
        public static string NO_NEW_VERSION = "No new version";
        public static string BUILD_IN_ERROR = "Latest build is broken";
        public static string NEW_VERSION = "New Resharper 5.0 Nightly";
        public static string YOU_ALREADY_HAVE = "you already have latest build {0} installed";
        public static string BUILD_PROBLEM = "the build {0} {1} has a problem {2}";
        
        
        private IBuild build;
        
        public void install_latest()
        {
            try
            {
                build = retrieve_latest();
                if (build != null && !build.Installed && build.Status != BuildStatus.Error)
                {
                    install(build); 
                }
                else if (build.Status != BuildStatus.Error)
                    build_in_error();
                else
                    build_already_installed();
            }
            catch
            {
            }
        }

        public void install(IBuild build)
        {

            status(InstallStatus.DOWNLOADING);
            display("Downloading", string.Format("{0} {1}", build.Date, build.Number));
            var msi_location = new Downloader().install(build.Url);
            var psi = new System.Diagnostics.ProcessStartInfo(msi_location);
            status(InstallStatus.INSTALLING);
            var listFiles = System.Diagnostics.Process.Start(psi);
            listFiles.WaitForExit(10*60*1000);
            if (retrieve_latest().Installed) status(InstallStatus.CURRENT);

        }

        void build_in_error()
        {
            status(InstallStatus.ERROR);
            var comments = Regex.Replace(build.Comments,"<[^>]*>","");
            display(BUILD_IN_ERROR,string.Format(BUILD_PROBLEM, build.Date, build.Number,comments));
        }

        private IBuild retrieve_latest()
        {
            IList<IBuild> builds = null;
            try
            {
                builds = new UpdaterTask().available_builds();
                previous(builds.Take(10));
            }
            catch(WebException ex)
            {
                display("Couldn't connect", "there was a problem connecting to jetbrains");
            }
            if (builds.Count > 0)
                return builds[0];
            return null;
        }

        private void build_already_installed()
        {
            status(InstallStatus.CURRENT);
            display(NO_NEW_VERSION,string.Format(YOU_ALREADY_HAVE, build.Number));
        }

        public void check_for_build_available()
        {
            status(InstallStatus.CHECKING);
                build = retrieve_latest();
            
            if (build != null)
            {
                if (!build.Installed && build.Status != BuildStatus.Error)
                    new_version_available();
                else if (build.Status == BuildStatus.Error)
                    build_in_error();
                else 
                    build_already_installed();
            }
            else
                build_already_installed();

        }

        private void new_version_available()
        {
            status(InstallStatus.AVAILABLE);
            display(NEW_VERSION,build.Date + " Build:" + build.Number);
        }

        public void silent_check_for_update()
        {
            status(InstallStatus.CHECKING);
            build = retrieve_latest();
            if(build!=null)
                if(build.Status == BuildStatus.Error)
                    build_in_error();
                else if (!build.Installed)
                    new_version_available();
                else
                    status(InstallStatus.CURRENT);
            else
                status(InstallStatus.CURRENT);
        }



        public IEnumerable<IBuild> all_builds()
        {
            yield return new Build { Number = 123, Rating = 3.5m, Date = "01 Apr 2009" };
        }

        public display_a_message display { get; set; }
        public status_change status { get; set; }
        public update_previous_list previous { get; set; }
    }
    
    public delegate void display_a_message(string title,string description);
    public delegate void status_change(InstallStatus status);
    public delegate void update_previous_list(IEnumerable<IBuild> builds);

    public enum InstallStatus {CURRENT,AVAILABLE,INSTALLING,DOWNLOADING,ERROR,
        CHECKING
    }
}
